package controller.parameterpanels;

import java.util.ArrayList;
import java.util.List;

import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.JTextField;

import model.IManufacturingMethod;
import model.auxillary.Parameter;
import model.auxillary.ParameterCollection;
import model.auxillary.ParameterList;
import model.auxillary.ParameterList.ParameterType;
import view.AlphaTextField;
import view.CenterTabbedPane;
import view.EBenchmarkPanel;
import view.IObserver;
import view.NumericalTextField;
import view.parameterpanels.StandardParameterInputPanel;
import controller.CtrInformationPanel;
import controller.IControllable;

/**
 * The class {@code CtrInputParameterPanel} is a controller class
 * for every standard parameter input panel. It controls the behavior of
 * it's view.
 * @author Oliver Eckstein
 *
 */
public class CtrInputParameterPanel implements IControllable, IObserver {

	/**
	 * The referenced model.
	 */
	protected IManufacturingMethod manuMethod;
	
	/**
	 * The controller of the information panel.
	 */
    protected CtrInformationPanel infoPanelCtr;
    
    /**
     * The type of parameter the controller's view shows. I.e. geometry
     * parameters, process parameters etc.
     */
    protected ParameterType parameterType;
    
    /**
     * This controller's view.
     */
    protected StandardParameterInputPanel paramPanel;
    
    /**
     * The original name of the connected manufacturing method. This variable
     * is used when the user changed the name of a manufacturing method and
     * the input parameter tabs are still opened.
     */
    private String oldManuMethodName;
    
    /**
     * To create a new {@code CtrInputParameterPanel}.
     * @param manuMethod the manufacturing method connected to the controller.
     * @param infoPanelCtr the information panel controller.
     * @param parameterType the type of parameter whose panel gets created.
     * @param logoPath a path to an optional logo that is shown on the
     * parameter panel.
     */
	public CtrInputParameterPanel(IManufacturingMethod manuMethod,
			CtrInformationPanel infoPanelCtr, ParameterType parameterType,
			String logoPath) {
		this.manuMethod = manuMethod;
        this.infoPanelCtr = infoPanelCtr;
        this.parameterType = parameterType;
        oldManuMethodName = manuMethod.getName();
        createView(logoPath);
        init();        
	}
	
	/**
     * To tell the controller that another invalid input was written into
     * one of the text fields.
     */
    public void addInvalidInput() {
    	infoPanelCtr.getView().showInvalidInputError();
    	paramPanel.setErrorStatus(true);
        infoPanelCtr.disableStoreData();
        infoPanelCtr.disableCalculation();
        manuMethod.notifyObservers();
    }
    
    /**
     * To tell the controller that another invalid input was corrected.
     */
    public void removeInvalidInput() {
    	infoPanelCtr.getView().showManipulateMethodStandardMessage();
        paramPanel.setErrorStatus(false);
        infoPanelCtr.enableStoreData();
        manuMethod.notifyObservers();
    }
    
    /**
     * To tell the controller that another valid input was written.
     */
    public void addValidInput() {
        if(manuMethod.allSet()) {
            infoPanelCtr.enableCalculation();            
        }        
    }
    
    /**
     * To tell the controller that a valid input was removed.
     */
    public void removeValidInput() {
    	infoPanelCtr.disableCalculation();
    }
	
    @Override
	public EBenchmarkPanel getView() {
		return paramPanel;
	}
    
    /**
     * To add a document listener to every text field of a parameter panel.
     * The view of this controller gets registered as an observer in the model.
     * @param textFields the text fields.
     */
    protected void addTextFieldListeners(
    		List<JTextField> textFields) {
    	Parameter param;
    	String paramID;
    	for(JTextField textField : textFields) {    		
    		NumericalTextField numTF = (NumericalTextField) textField;
    		paramID = numTF.getParameterID();
    		param = manuMethod.getParameter(paramID);
    		numTF.addDocumentListener(
    				new ListenerNumericalTF(numTF, param, this));
    	}
    }   
    
    /**
     * To change the text of a parameter panel's border. 
     * @param newText the text to be set for the border.
     */
    public void changeBorderText(String newText) {
    	paramPanel.setBorderText(0, newText);
    }
    
    /**
     * To remove the last parameter panel from the view.
     */
    public void removeParameterPanel() {
    	paramPanel.removeParameterPanel();
    }
    
    /**
     * To create the necessary information to create a new parameter panel.
     * @param collection the parameters whose parameter panels get created.
     * @return the parameter information.
     */
    protected List<String[]> createParamInfo(ParameterCollection collection) {
    	List<String[]> paramsInfo = new ArrayList<String[]>();
		for (Parameter param : collection.getParameters()) {
			String[] paramInfo = new String[5];
			paramInfo[0] = param.getName();
			paramInfo[1] = param.getKey();
			paramInfo[2] = param.getGuiAbbreviation();
			paramInfo[3] = param.getUnit();
			
			if (Double.isNaN(param.getValue()) || 
					param.getValue() == null) {
				paramInfo[4] = "";
			} else {
				paramInfo[4] = String.valueOf(param.getValue());
			}
			paramsInfo.add(paramInfo);
		}
		return paramsInfo;
    }

    @Override
    public void createView(String logoPath) {
		paramPanel = new StandardParameterInputPanel(
				logoPath,
				CenterTabbedPane.parameterTypeToTab(parameterType),
				ParameterList.typeToString(parameterType),
				manuMethod);

	}

	/**
     * To initiate the view of this controller.
     */
	protected void init() {
		List<ParameterCollection> collections = 
    			manuMethod.getParameters(parameterType);
    	for (ParameterCollection collection : collections) {
    		addParameterPanel(collection);  				
    	}
    	if(manuMethod.allSet()) {
            infoPanelCtr.enableCalculation();            
        }
	}

	/**
     * To add a parameter panel to the view.
     * @param collection the parameter collection whose parameter panels get
     * drawn.
     */
	protected void addParameterPanel(ParameterCollection collection) {
		addTextFieldListeners(
				paramPanel.addParameterSet(
						createParamInfo(collection),
						collection.getName()));
	}

	/**
     * To change the text of a parameter panel's border. Like the border
     * of a single geometry parameter panel or a tool parameter panel.
     * @param textField the text field that caused the text change. It is
     * needed to identify the correct parameter panel inside the
     * controller's view.
     * @param newText the text to be set for the border.
     */
	public void changeBorderText(AlphaTextField textField, String newText) {
		// Nothing to do here.
		// This method gets overridden in inherited classes.
	}

	@Override
	public void update() {

		// To rename the border titles for bordered parameter input panels.
		if(!oldManuMethodName.equals(manuMethod.getName())) {
			for(JPanel panel : paramPanel.getparameterPanels()) {
				List<ParameterCollection> collection = manuMethod.getParameters(
	    				parameterType);
				if(collection.size() == 1) {
					/*
					 * Getting always the 0. element is no good style of
					 * programming. But this mechanism
					 * is only used when there is just one parameter panel on
					 * the panel. For panels with more than one parameter input 
					 * panel the user changes the text via AlphaTextFields in
					 * the method changeBorderText(...).
					 */
					panel.setBorder(BorderFactory.createTitledBorder(
	                		collection.get(0).getName()));	
				}					
			}
			oldManuMethodName = manuMethod.getName();
		}
	}
}
